home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / TREEWN16.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  20.4 KB  |  1,162 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1995, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.17  $
  6. //
  7. // Implementation of class TTreeWindow for Win16
  8. //----------------------------------------------------------------------------
  9. #include <owl/pch.h>
  10. #if !defined(OWL_TREEWIND_H)
  11. # include <owl/treewind.h>
  12. #endif
  13. #if !defined(__STDIO_H)
  14. # include <stdio.h>
  15. #endif
  16. #if !defined(__TCHAR_H)
  17. # include <tchar.h>
  18. #endif
  19.  
  20. OWL_DIAGINFO;
  21.  
  22. const int TTreeWindow::ButtonHeight = 11;
  23. const int TTreeWindow::ButtonWidth  = 10;
  24.  
  25. //
  26. // Create the control dynamically.
  27. //
  28. TTreeWindow::TTreeWindow(TWindow* parent, int id, int x, int y, int w, int h,
  29.                          uint32 style, TModule* module)
  30. :
  31.   TListBox(parent, id, x, y, w, h, module),
  32.   Style(style)
  33. {
  34.   Attr.Style |= LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_NOINTEGRALHEIGHT;
  35.   Attr.Style &= ~LBS_HASSTRINGS;
  36.   Attr.Style &= ~LBS_SORT;
  37.   Init();
  38. }
  39.  
  40. //
  41. // Create the control from a resource
  42. //
  43. TTreeWindow::TTreeWindow(TWindow* parent, int resourceId, TModule* module)
  44. :
  45.   TListBox(parent, resourceId, module)
  46. {
  47.   Init();
  48. }
  49.  
  50. //
  51. // Private Init to initialize the control
  52. //
  53. void
  54. TTreeWindow::Init()
  55. {
  56.   Font        = new TFont("MS Sans Serif", 16);
  57.   RootLink    = new TTreeLink(*this);
  58.   IndentUnits = 20;
  59. }
  60.  
  61. //
  62. //
  63. //
  64. TTreeWindow::~TTreeWindow()
  65. {
  66.   delete Font;
  67.   delete RootLink;
  68. }
  69.  
  70.  
  71. DEFINE_RESPONSE_TABLE1(TTreeWindow, TListBox)
  72.   EV_WM_GETFONT,
  73.   EV_WM_SETFONT,
  74.   EV_WM_CHAR,
  75.   EV_NOTIFY_AT_CHILD(LBN_DBLCLK, EvLDblClk),
  76. END_RESPONSE_TABLE;
  77.  
  78.  
  79. //
  80. //
  81. //
  82. void
  83. TTreeWindow::EvChar(uint key, uint repeatCount, uint flags)
  84. {
  85.   int index = GetCaretIndex();
  86.   TTreeLink* link = GetLinkAtIndex(index);
  87.  
  88.   if (link) {
  89.     if (key == '+') {
  90.       if (link->IsParent() && !link->IsOpened())   // expand
  91.         OpenLink(link, index);
  92.     }
  93.     else if (key == '-') {
  94.       if (link->IsParent() && link->IsOpened())   // compress
  95.         CloseLink(link, index);
  96.     }
  97.   }
  98.   TListBox::EvChar(key, repeatCount, flags);
  99. }
  100.  
  101. //
  102. //
  103. //
  104. void
  105. TTreeWindow::EvLDblClk()
  106. {
  107.   int index = GetSelIndex();
  108.   TTreeLink* link = GetLinkAtIndex(index);
  109.  
  110.   if (link && link->IsParent())
  111.     if (link->IsOpened())
  112.       CloseLink(link, index);
  113.     else
  114.       OpenLink(link, index);
  115.  
  116.   DefaultProcessing();
  117. }
  118.  
  119. //
  120. //
  121. //
  122. void
  123. TTreeWindow::EvSetFont(HFONT hFont, bool redraw)
  124. {
  125.   TListBox::EvSetFont(hFont, redraw);
  126.   delete Font;
  127.   Font = new TFont(hFont);
  128. }
  129.  
  130. //
  131. //
  132. //
  133. HFONT
  134. TTreeWindow::EvGetFont()
  135. {
  136.   if (Font)
  137.     return *Font;
  138.   else
  139.     return (HFONT)DefaultProcessing();
  140. }
  141.  
  142. //
  143. //
  144. //
  145. int
  146. TTreeWindow::AddLinks(TTreeLink* link, int indentLevel, int insertAfterIndex)
  147. {
  148.   if (link == 0)
  149.     return insertAfterIndex;
  150.  
  151.   if (!link->IsRoot())
  152.     insertAfterIndex = InsertString((char far*)link, insertAfterIndex);
  153.   else {
  154.     insertAfterIndex = -1;
  155.     indentLevel = 0;
  156.   }
  157.  
  158.   if ((link->IsParent() && link->IsOpened()) || link->IsRoot()) {
  159.     TTreeLink* chase = link->LastChild;
  160.     while (chase) {
  161.       AddLinks(chase, indentLevel + 1, insertAfterIndex + 1);
  162.       chase = chase->PrevSibling;
  163.     }
  164.   }
  165.  
  166.   link->SetIndentLevel(indentLevel);
  167.  
  168.   return 0;
  169. }
  170.  
  171. //
  172. //
  173. //
  174. void
  175. TTreeWindow::OpenLink(TTreeLink* link, int index)
  176. {
  177.   if (link == 0)
  178.     return;
  179.  
  180.   link->ToggleOpened();
  181.   TTreeLink* chase = link->LastChild;
  182.   while (chase) {
  183.     AddLinks(chase, link->GetIndentLevel() + 1, index + 1);
  184.     chase = chase->PrevSibling;
  185.   }
  186. }
  187.  
  188. //
  189. //
  190. //
  191. void
  192. TTreeWindow::CloseLink(TTreeLink* link, int index)
  193. {
  194.   if (link == 0)
  195.     return;
  196.  
  197.   link->ToggleOpened();
  198.   index++;
  199.  
  200.   if (index >= GetCount())
  201.     return;
  202.  
  203.   int targetDeleteLevel = link->GetIndentLevel() + 1;
  204.   TTreeLink* chase      = GetLinkAtIndex(index);
  205.   int chaseIndentLevel  = chase->GetIndentLevel();
  206.  
  207.   // When closing a parent, remove all of the children with indent level
  208.   // greater than the parents.
  209.   //
  210.   while (targetDeleteLevel <= chaseIndentLevel) {
  211.     if (chase->IsOpened())
  212.       CloseLink(chase, index);
  213.  
  214.     int count = DeleteString(index);
  215.     if (index >= count)
  216.       break;
  217.  
  218.     chase            = GetLinkAtIndex(index);
  219.     chaseIndentLevel = chase->GetIndentLevel();
  220.   }
  221. }
  222.  
  223. //
  224. //
  225. //
  226. void
  227. TTreeWindow::Update()
  228. {
  229.   int topIndex = GetTopIndex();
  230.   int selIndex = GetSelIndex();
  231.   SendMessage(WM_SETREDRAW, false);
  232.   ClearList();
  233.  
  234.   AddLinks(RootLink, 0, 0);
  235.  
  236.   SetTopIndex(topIndex);
  237.   if (selIndex != LB_ERR)
  238.     SetSelIndex(selIndex);
  239.   SendMessage(WM_SETREDRAW, true);
  240. }
  241.  
  242. //
  243. //
  244. //
  245. TTreeLink*
  246. TTreeWindow::GetLinkAtIndex(int index)
  247. {
  248.   if (index < 0 || index >= GetCount())
  249.     return 0;
  250.   return (TTreeLink*)GetItemData(index);
  251. }
  252.  
  253. //
  254. //
  255. //
  256. void
  257. TTreeWindow::SetIndent(uint units)
  258. {
  259.   IndentUnits = units;
  260.  
  261.   if (IndentUnits < ButtonWidth + 2)
  262.     IndentUnits = ButtonWidth + 2;
  263.  
  264.   if (*this != 0)
  265.     Invalidate();
  266. }
  267.  
  268. //
  269. //
  270. //
  271. void
  272. TTreeWindow::MeasureItem(MEASUREITEMSTRUCT far& measureItemInfo)
  273. {
  274.   TTreeLink* link = GetLinkAtIndex(measureItemInfo.itemID);
  275.   if (link == 0)
  276.     return;
  277.  
  278.   const int defCx = -1;
  279.   const int defCy = -1;
  280.  
  281.   TSize size(defCx, defCy);
  282.   link->GetSize(size, Font);
  283.  
  284.   if (size.cx != defCx)
  285.     measureItemInfo.itemWidth = size.cx;
  286.  
  287.   if (size.cx != defCy)
  288.     measureItemInfo.itemHeight = size.cy;
  289.  
  290.   if (measureItemInfo.itemHeight < ButtonHeight + 2)
  291.     measureItemInfo.itemHeight = ButtonHeight + 2;
  292. }
  293.  
  294. //
  295. //
  296. //
  297. void
  298. TTreeWindow::ODAFocus(DRAWITEMSTRUCT far& drawInfo)
  299. {
  300.   PaintLink(drawInfo);
  301. }
  302.  
  303. //
  304. //
  305. //
  306. void
  307. TTreeWindow::ODASelect(DRAWITEMSTRUCT far& drawInfo)
  308. {
  309.   PaintLink(drawInfo);
  310. }
  311.  
  312. //
  313. //
  314. //
  315. void
  316. TTreeWindow::ODADrawEntire(DRAWITEMSTRUCT far& drawInfo)
  317. {
  318.   PaintLink(drawInfo);
  319. }
  320.  
  321. //
  322. //
  323. //
  324. void
  325. TTreeWindow::PaintLink(DRAWITEMSTRUCT far& drawInfo)
  326. {
  327.   TTreeLink* link = GetLinkAtIndex(drawInfo.itemID);
  328.   if (link == 0)
  329.     return;
  330.  
  331.   // Prepare dc
  332.   //
  333.   TDC dc(drawInfo.hDC);
  334.   if (Font)
  335.     dc.SelectObject(*Font);
  336.  
  337.   // Erase entire line
  338.   //
  339.   TRect rect(drawInfo.rcItem);
  340.   TBrush bkgnd(TColor::SysWindow);
  341.   dc.FillRect(rect, bkgnd);
  342.  
  343.   // Figure out "non user area"
  344.   //
  345.   TRect drawRect(rect);
  346.   drawRect.right = GetIndent() * link->GetIndentLevel();
  347.  
  348.   // Draw connecting lines if necessary
  349.   //
  350.   if (HasStyle(TVS_HASLINES)) {
  351.     TPen pen(TColor::Gray, 1, PS_DOT);
  352.     dc.SelectObject(pen);
  353.  
  354.     int indentLevel = link->GetIndentLevel();
  355.     TTreeLink* chase = link;
  356.     bool firstDraw = true;
  357.  
  358.     TRect temp = drawRect;
  359.     temp.left = temp.right - GetIndent();
  360.  
  361.     while (indentLevel > 0) {
  362.       int centerX = temp.left + (temp.right - temp.left) / 2;
  363.       int centerY = temp.top + (temp.bottom - temp.top) / 2;
  364.  
  365.       if (firstDraw) {
  366.         firstDraw = false;
  367.         if (chase->IsFirstChild() && indentLevel == 1) {
  368.           dc.MoveTo(centerX, temp.bottom);
  369.           dc.LineTo(centerX, centerY);
  370.           dc.LineTo(temp.right, centerY);
  371.         }
  372.         else if (chase->IsLastChild()) {
  373.           dc.MoveTo(centerX, temp.top);
  374.           dc.LineTo(centerX, centerY);
  375.           dc.LineTo(temp.right, centerY);
  376.         }
  377.         else {
  378.           dc.MoveTo(centerX, temp.top);
  379.           dc.LineTo(centerX, temp.bottom);
  380.           dc.MoveTo(centerX, centerY);
  381.           dc.LineTo(temp.right, centerY);
  382.         }
  383.       }
  384.       else {
  385.         if (!chase->IsLastChild()) {
  386.           dc.MoveTo(centerX, temp.top);
  387.           dc.LineTo(centerX, temp.bottom);
  388.           dc.MoveTo(centerX, centerY);
  389.         }
  390.       }
  391.  
  392.       temp.left -= GetIndent();
  393.       temp.right -= GetIndent();
  394.       indentLevel--;
  395.       chase = chase->ParentLink;
  396.     }
  397.  
  398.     dc.RestorePen();
  399.   }
  400.  
  401.   // Draw parent blocks
  402.   //
  403.   if (HasStyle(TVS_HASBUTTONS)) {
  404.     TRect temp = drawRect;
  405.     temp.left = temp.right - GetIndent();
  406.  
  407.     int width = GetIndent();
  408.     temp.left += width / 2;
  409.     temp.left -= ButtonWidth / 2;
  410.     temp.right -= width / 2;
  411.     temp.right += ButtonWidth / 2;
  412.  
  413.     int height = temp.bottom - temp.top;
  414.     temp.top += height / 2;
  415.     temp.top -= ButtonHeight / 2;
  416.     temp.bottom -= height / 2;
  417.     temp.bottom += ButtonHeight / 2;
  418.  
  419.     if (link->IsParent()) {
  420.       const int offset = 2;
  421.       dc.Rectangle(temp);
  422.  
  423.       // always draw -
  424.       //
  425.       int y = temp.top + (temp.bottom - temp.top) / 2;
  426.       dc.MoveTo(temp.left + offset, y);
  427.       dc.LineTo(temp.right - offset, y);
  428.  
  429.       // figure if need to draw |
  430.       //
  431.       if (!link->IsOpened()) {
  432.         int x = temp.left + (temp.right - temp.left) / 2;
  433.         dc.MoveTo(x, temp.top + offset);
  434.         dc.LineTo(x, temp.bottom - offset);
  435.       }
  436.     }
  437.   }
  438.  
  439.   // Find item's width
  440.   //
  441.   rect.left += GetIndent() * link->GetIndentLevel();
  442.   TSize size;
  443.   link->GetSize(size, Font);
  444.   rect.right = rect.left + size.cx;
  445.  
  446.   // Draw the item
  447.   //
  448.   dc.DrawText(link->TreeItem->Text, -1, rect, DT_SINGLELINE | DT_VCENTER);
  449.  
  450.   // Draw focus and selected states
  451.   //
  452.   if (drawInfo.itemState & ODS_FOCUS)
  453.     dc.DrawFocusRect(rect);
  454.  
  455.   if (drawInfo.itemState & ODS_SELECTED)
  456.     dc.InvertRect(rect);
  457. }
  458.  
  459. //
  460. //
  461. //
  462. TTreeNode
  463. TTreeWindow::GetSelection()
  464. {
  465.   TTreeLink* link = GetLinkAtIndex(GetSelIndex());
  466.   return TTreeNode(*link);
  467. }
  468.  
  469. //
  470. //
  471. //
  472. void
  473. TTreeWindow::SetStyle(uint32 style)
  474. {
  475.   TWindow::SetStyle(WS_CHILD | style);
  476. }
  477.  
  478. //
  479. //
  480. //
  481. bool
  482. TTreeWindow::HasStyle(uint32 style)
  483. {
  484.   return (GetStyle() & style) ? true : false;
  485. }
  486.  
  487. //----------------------------------------------------------------------------
  488. // TTreeLink
  489.  
  490. //
  491. //
  492. //
  493. TTreeLink::TTreeLink(TTreeWindow& window)
  494. :
  495.   Window(window),
  496.   Opened(false),
  497.   TreeItem(0),
  498.   ParentLink(0),
  499.   FirstChild(0),
  500.   LastChild(0),
  501.   PrevSibling(0),
  502.   NextSibling(0),
  503.   IndentLevel(0)
  504. {
  505. }
  506.  
  507.  
  508. //
  509. // if FirstChild == LastChild {
  510. //   only has 0 or 1 child
  511. // } else {
  512. //   multiple child
  513. // }
  514. //
  515. TTreeLink::~TTreeLink()
  516. {
  517.   // Get rid of children
  518.   //
  519.   TTreeLink* chase = FirstChild;
  520.  
  521.   while (chase != LastChild) {
  522.     TTreeLink* nextChild = chase->NextSibling;
  523.     delete chase;
  524.     chase = nextChild;
  525.   }
  526.   delete chase;
  527.  
  528.   delete TreeItem;
  529.  
  530.   // Special case root node
  531.   //
  532.   if (ParentLink == 0)
  533.     return;
  534.  
  535.   // Fix parent's children pointers
  536.   //
  537.   if (PrevSibling == 0)
  538.     ParentLink->FirstChild = NextSibling;
  539.  
  540.   if (NextSibling == 0)
  541.     ParentLink->LastChild = PrevSibling;
  542.  
  543.   // Fix sibling pointers
  544.   //
  545.   if (PrevSibling)
  546.     PrevSibling->NextSibling = NextSibling;
  547.  
  548.   if (NextSibling)
  549.     NextSibling->PrevSibling = PrevSibling;
  550. }
  551.  
  552. //
  553. //
  554. //
  555. TTreeLink*
  556. TTreeLink::AddAtHead(const TTreeItem& itemToAdd)
  557. {
  558.   TTreeItem* newItem = new TTreeItem(itemToAdd);
  559.   TTreeLink* newLink = new TTreeLink(Window);
  560.   newLink->TreeItem = newItem;
  561.   newLink->ParentLink = ParentLink;
  562.  
  563.   TTreeLink* head;
  564.  
  565.   // Find head of list
  566.   //
  567.   if (ParentLink) {
  568.     head = ParentLink->FirstChild;
  569.   }
  570.   else {
  571.     head = this;
  572.     while (head->PrevSibling)
  573.       head = head->PrevSibling;
  574.   }
  575.  
  576.   newLink->NextSibling = head;
  577.   head->PrevSibling = newLink;
  578.  
  579.   if (ParentLink)
  580.     ParentLink->FirstChild = newLink;
  581.  
  582.   return newLink;
  583. }
  584.  
  585. //
  586. //
  587. //
  588. TTreeLink*
  589. TTreeLink::AddAtTail(const TTreeItem& itemToAdd)
  590. {
  591.   TTreeItem* newItem = new TTreeItem(itemToAdd);
  592.   TTreeLink* newLink = new TTreeLink(Window);
  593.   newLink->TreeItem = newItem;
  594.   newLink->ParentLink = ParentLink;
  595.  
  596.   TTreeLink* tail;
  597.  
  598.   // Find tail of list
  599.   //
  600.   if (ParentLink) {
  601.     tail = ParentLink->LastChild;
  602.   }
  603.   else {
  604.     tail = this;
  605.     while (tail->NextSibling)
  606.       tail = tail->NextSibling;
  607.   }
  608.  
  609.   newLink->PrevSibling = tail;
  610.   tail->NextSibling = newLink;
  611.  
  612.   if (ParentLink)
  613.     ParentLink->LastChild = newLink;
  614.  
  615.   return newLink;
  616. }
  617.  
  618. //
  619. //
  620. //
  621. TTreeLink*
  622. TTreeLink::AddAfter(const TTreeItem& itemToAdd)
  623. {
  624.   TTreeItem* newItem = new TTreeItem(itemToAdd);
  625.   TTreeLink* newLink = new TTreeLink(Window);
  626.   newLink->TreeItem = newItem;
  627.   newLink->ParentLink = ParentLink;
  628.  
  629.   if (ParentLink && ParentLink->LastChild == this)
  630.     ParentLink->LastChild = newLink;
  631.  
  632.   newLink->PrevSibling = this;
  633.   newLink->NextSibling = NextSibling;
  634.   if (NextSibling)
  635.     NextSibling->PrevSibling = newLink;
  636.   NextSibling = newLink;
  637.  
  638.   return newLink;
  639. }
  640.  
  641. //
  642. //
  643. //
  644. TTreeLink*
  645. TTreeLink::AddFirstChild(const TTreeItem& itemToAdd)
  646. {
  647.   TTreeItem* newItem = new TTreeItem(itemToAdd);
  648.   TTreeLink* newLink = new TTreeLink(Window);
  649.   newLink->TreeItem = newItem;
  650.   newLink->ParentLink = this;
  651.  
  652.   if (FirstChild)
  653.     FirstChild->PrevSibling = newLink;
  654.  
  655.   newLink->NextSibling = FirstChild;
  656.  
  657.   FirstChild = newLink;
  658.   if (LastChild == 0)
  659.     LastChild = newLink;
  660.  
  661.   return newLink;
  662. }
  663.  
  664. //
  665. //
  666. //
  667. TTreeLink*
  668. TTreeLink::AddLastChild(const TTreeItem& itemToAdd)
  669. {
  670.   TTreeItem* newItem = new TTreeItem(itemToAdd);
  671.   TTreeLink* newLink = new TTreeLink(Window);
  672.   newLink->TreeItem = newItem;
  673.   newLink->ParentLink = this;
  674.  
  675.   if (LastChild)
  676.     LastChild->NextSibling = newLink;
  677.  
  678.   newLink->PrevSibling = LastChild;
  679.  
  680.   LastChild = newLink;
  681.   if (FirstChild == 0)
  682.     FirstChild = newLink;
  683.  
  684.   return newLink;
  685. }
  686.  
  687. //
  688. //
  689. //
  690. bool
  691. TTreeLink::Delete()
  692. {
  693.   // Cannot delete the root
  694.   //
  695.   if (IsRoot())
  696.     return false;
  697.  
  698.   // deleting only child
  699.   //
  700.   if (!PrevSibling && !NextSibling)  {
  701.     ParentLink->FirstChild = ParentLink->LastChild = 0;
  702.     delete this;
  703.     return true;
  704.   }
  705.  
  706.   // deleting tail
  707.   //
  708.   if (PrevSibling && !NextSibling) {
  709.     ParentLink->LastChild = PrevSibling;
  710.     PrevSibling->NextSibling = 0;
  711.     delete this;
  712.     return true;
  713.   }
  714.  
  715.   // deleting head
  716.   //
  717.   if (!PrevSibling && NextSibling) {
  718.     ParentLink->FirstChild = NextSibling;
  719.     NextSibling->PrevSibling = 0;
  720.     delete this;
  721.     return true;
  722.   }
  723.  
  724.   // deleting middle of list
  725.   //
  726.   NextSibling->PrevSibling = PrevSibling;
  727.   PrevSibling->NextSibling = NextSibling;
  728.   delete this;
  729.   return true;
  730. }
  731.  
  732. //
  733. //
  734. //
  735. void
  736. TTreeLink::GetSize(TSize& size, TFont* font)
  737. {
  738.   if (font) {
  739.     size = font->GetTextExtent(TreeItem->Text);
  740.   }
  741. }
  742.  
  743. //
  744. //
  745. //
  746. void
  747. TTreeLink::ToggleOpened()
  748. {
  749.   Opened = Opened ? false : true;
  750. }
  751.  
  752. //
  753. //
  754. //
  755. bool
  756. TTreeLink::IsLastChild()
  757. {
  758.   if (ParentLink == 0)
  759.     return false;
  760.  
  761.   if (ParentLink->LastChild == this)
  762.     return true;
  763.  
  764.   return false;
  765. }
  766.  
  767. //
  768. //
  769. //
  770. bool
  771. TTreeLink::IsFirstChild()
  772. {
  773.   if (ParentLink == 0)
  774.     return false;
  775.  
  776.   if (ParentLink->FirstChild == this)
  777.     return true;
  778.  
  779.   return false;
  780. }
  781.  
  782.  
  783. //----------------------------------------------------------------------------
  784. // TTreeNode
  785.  
  786. //
  787. // Initialize based on the root for TTreeWindow
  788. //
  789. TTreeNode::TTreeNode(TTreeWindow& tree)
  790. :
  791.   TreeView(&tree)
  792. {
  793.   *this = tree.GetRoot();
  794. }
  795.  
  796. //
  797. //
  798. //
  799. TTreeNode::TTreeNode(TTreeWindow& tree, char far* text)
  800. :
  801.   TreeView(&tree)
  802. {
  803.   SetText(text);
  804. }
  805.  
  806. //
  807. //
  808. //
  809. TTreeNode::TTreeNode(TTreeLink& link)
  810. :
  811.   TreeView(&link.Window)
  812. {
  813.   Link = &link;
  814. }
  815.  
  816. //
  817. // Copy constructor
  818. //
  819. TTreeNode::TTreeNode(const TTreeNode& other)
  820. :
  821.   TreeView(other.TreeView)
  822. {
  823.   CopyNode(other);
  824. }
  825.  
  826. //
  827. // Navigational constructor
  828. //
  829. TTreeNode::TTreeNode(const TTreeNode& other, uint32 nextCode)
  830. :
  831.   TreeView(other.TreeView)
  832. {
  833.   TTreeNode node = other;
  834.   *this = node.GetNextItem(nextCode);
  835. }
  836.  
  837. //
  838. //
  839. //
  840. TTreeNode
  841. TTreeNode::operator =(const TTreeNode& other)
  842. {
  843.   return CopyNode(other);
  844. }
  845.  
  846. //
  847. //  Reset node to make it a copy of another node
  848. //
  849. TTreeNode&
  850. TTreeNode::CopyNode(const TTreeNode& node)
  851. {
  852.   TreeView    = node.TreeView;
  853.   ItemStruct  = node.ItemStruct;    // this gets the text, too
  854.   Link        = node.Link;
  855.   return *this;
  856. }
  857.  
  858. //
  859. //
  860. //
  861. TTreeNode::~TTreeNode()
  862. {
  863.   // don't do anything
  864. }
  865.  
  866. //
  867. //
  868. //
  869. bool
  870. TTreeNode::ExpandItem(uint32 flag)
  871. {
  872.   if (!Link->IsParent())
  873.     return false;
  874.  
  875.   for (int index = 0; index < Link->Window.GetCount(); index++) {
  876.     TTreeLink* link = Link->Window.GetLinkAtIndex(index);
  877.  
  878.     if (!link->IsParent())
  879.       continue;
  880.  
  881.     if (Link == link) {
  882.       if (flag == Toggle) {
  883.         if (link->IsOpened())
  884.           link->Window.CloseLink(link, index);
  885.         else
  886.           link->Window.OpenLink(link, index);
  887.         return true;
  888.       }
  889.       else if (flag == Expand) {
  890.         if (!link->IsOpened())
  891.           link->Window.OpenLink(link, index);
  892.         return true;
  893.       }
  894.       else if (flag == Collapse) {
  895.         if (link->IsOpened())
  896.           link->Window.CloseLink(link, index);
  897.         return true;
  898.       }
  899.     }
  900.   }
  901.  
  902.   return false;
  903. }
  904.  
  905. //
  906. //
  907. //
  908. TTreeNode
  909. TTreeNode::GetNextItem(uint32 flag) const
  910. {
  911.   switch (flag) {
  912.     case Root:
  913.       return Link->Window.GetRoot();
  914.  
  915.     case Next: {
  916.       if (Link->NextSibling)
  917.         return TTreeNode(*Link->NextSibling);
  918.       break;
  919.     }
  920.  
  921.     case Previous: {
  922.       if (Link->PrevSibling)
  923.         return TTreeNode(*Link->PrevSibling);
  924.       break;
  925.     }
  926.  
  927.     case Parent: {
  928.       if (Link->ParentLink)
  929.         return TTreeNode(*Link->ParentLink);
  930.       break;
  931.     }
  932.  
  933.     case Child: {
  934.       if (Link->FirstChild)
  935.         return TTreeNode(*Link->FirstChild);
  936.       break;
  937.     }
  938.  
  939.   }
  940.   throw TXOwl("Default case occured in TTreeNode::GetNextItem");
  941. }
  942.  
  943. //
  944. //
  945. //
  946. bool
  947. TTreeNode::GetItem(TTreeItem* item)
  948. {
  949.   *item = *(Link->TreeItem);
  950.   return true;
  951. }
  952.  
  953. //
  954. //
  955. //
  956. bool
  957. TTreeNode::SetItem()
  958. {
  959.   PRECONDITION(TreeView->GetHandle());
  960.   *(Link->TreeItem) = ItemStruct;
  961.   TreeView->Invalidate();
  962.   return true;
  963. }
  964.  
  965. //
  966. //
  967. //
  968. bool TTreeNode::GetItem()
  969. {
  970.   PRECONDITION(TreeView->GetHandle());
  971.   ItemStruct = *(Link->TreeItem);
  972.   return true;
  973. }
  974.  
  975. //
  976. //
  977. //
  978. TTreeNode
  979. TTreeNode::AddSibling(const TTreeItem& item) const
  980. {
  981.   return TTreeNode(*Link->AddAtTail(item));
  982. }
  983.  
  984. //
  985. //
  986. //
  987. TTreeNode
  988. TTreeNode::InsertChild(const TTreeItem& item, uint32 howToInsert) const
  989. {
  990.   TTreeLink* link;
  991.  
  992.   switch (howToInsert) {
  993.     case First: {
  994.       link = Link->AddAtHead(item);
  995.       break;
  996.     }
  997.  
  998.     case Last: {
  999.       link = Link->AddAtTail(item);
  1000.       break;
  1001.     }
  1002.  
  1003.     default:
  1004.       throw TXOwl("Not yet currently implemented in TTreeNode::InsertChild");
  1005.   }
  1006.   return TTreeNode(*link);
  1007. }
  1008.  
  1009. //
  1010. //
  1011. //
  1012. TTreeNode
  1013. TTreeNode::InsertItem(const TTreeItem& item) const
  1014. {
  1015.   return TTreeNode(*(Link->AddAfter(item)));
  1016. }
  1017.  
  1018. //
  1019. //
  1020. //
  1021. bool
  1022. TTreeNode::Delete()
  1023. {
  1024.   return Link->Delete();
  1025. }
  1026.  
  1027.  
  1028. bool
  1029. TTreeNode::SetText(const char far* text, bool /*ignored*/)
  1030. {
  1031.   ItemStruct.SetText(text);
  1032.   return true;
  1033. }
  1034.  
  1035. //
  1036. // Return a pointer to the node's text.
  1037. //
  1038. // The value returned in "text" points to the string in the tree's
  1039. // internal data structure.  The node owns the string.  Don't delete
  1040. // the string yourself. To modify the string, call SetText with a
  1041. // new value.
  1042. //
  1043. bool
  1044. TTreeNode::GetText(char far*& text, bool /*ignored*/)
  1045. {
  1046.   text = ItemStruct.Text;
  1047.   return true;
  1048. }
  1049.  
  1050. char far*
  1051. TTreeNode::GetText(bool /*ignored*/)
  1052. {
  1053.   return ItemStruct.Text;
  1054. }
  1055.  
  1056. bool
  1057. TTreeNode::SetItemData(uint32 data, bool /*ignored*/)
  1058. {
  1059.   ItemStruct.SetItemData(data);
  1060.   return true;
  1061. }
  1062.  
  1063. bool
  1064. TTreeNode::GetItemData(uint32& data, bool /*ignored*/)
  1065. {
  1066.   data = ItemStruct.GetItemData();
  1067.   return true;
  1068. }
  1069.  
  1070. //----------------------------------------------------------------------------
  1071. // TTreeItem
  1072.  
  1073. //
  1074. //
  1075. //
  1076. TTreeItem::TTreeItem()
  1077. {
  1078.   Init();
  1079. }
  1080.  
  1081. //
  1082. //
  1083. //
  1084. TTreeItem::TTreeItem(char far* text, int len)
  1085. {
  1086.   Init();
  1087.   SetText(text, len);
  1088. }
  1089.  
  1090. //
  1091. //
  1092. //
  1093. void
  1094. TTreeItem::Init()
  1095. {
  1096.   Text     = 0;
  1097.   Length   = 0;
  1098.   ItemData = 0;
  1099. }
  1100.  
  1101. //
  1102. //
  1103. //
  1104. TTreeItem::~TTreeItem()
  1105. {
  1106.   delete[] Text;
  1107. }
  1108.  
  1109. //
  1110. //
  1111. //
  1112. TTreeItem::TTreeItem(const TTreeItem& other)
  1113. {
  1114.   Init();
  1115.  
  1116.   delete[] Text;
  1117.   ItemData = other.ItemData;
  1118.  
  1119.   Length = other.Length;
  1120.   Text   = new char[Length + 1];
  1121.   _tcscpy(Text, other.Text);
  1122. }
  1123.  
  1124. //
  1125. //  Assign the text that belongs to this item.
  1126. //
  1127. void
  1128. TTreeItem::SetText(const char far* text, int size)
  1129. {
  1130.   delete[] Text;
  1131.   Text   = strnewdup(text);
  1132.   Length = max(size, _tcslen(text) + 1);
  1133. }
  1134.  
  1135. //
  1136. //
  1137. //
  1138. void
  1139. TTreeItem::GetText(char far* text, int len) const
  1140. {
  1141.   if (Length < len)
  1142.     _tcscpy(text, Text);
  1143.   else
  1144.     _tcsncpy(text, Text, len);
  1145. }
  1146.  
  1147. //
  1148. //
  1149. //
  1150. TTreeItem
  1151. TTreeItem::operator =(const TTreeItem& other)
  1152. {
  1153.   delete[] Text;
  1154.   ItemData = other.ItemData;
  1155.  
  1156.   Length = other.Length;
  1157.   Text   = new _TCHAR[Length + 1];
  1158.   _tcscpy(Text, other.Text);
  1159.  
  1160.   return *this;
  1161. }
  1162.